import { observer, watch, proxyDatas, proxyData, copyProperty } from './Observer'
import { viewRender, callNative, bindAll, diff, makeUnEnumerable } from './util'
import { templateParser } from './parser'
import listener from './Listener'
import initGlobalApit from './global-api'

export default class Hero {
  static options = {
    template: {},
    data: {},
    methods: {},
    created() {}
  }

  constructor (options) {
    const _options = this.$options = Object.assign({}, Hero.options, options)
    this.$data = _options.data

    this._init()
  }

  _init () {
    proxyDatas(this)
    observer(this.$data)
    makeUnEnumerable(this, '_oldTree', {})
    listener.push(bindAll(this.$options.events, this))
    copyProperty(bindAll(this.$options.methods, this), this)
    // webview 的 jsContext 需要 10ms  :(
    setTimeout(() => {
      callNative.command({viewWillAppear: {event: 'viewAppear'}})
      watch(() => this._created(), () => this._update())
    }, 0)
  }

  _created () {
    this.$options.created.call(this)
    // created 完成后 render
    this._render()
  }

  $set (key, value) {
    this.$data[key] = value
    proxyData(this, key)
  }

  /**
   * 代理 data 或 methods
   * @param {String} parts
   * @private
   */
  _proxy (parts) {
    Object.keys(this.$options[parts]).forEach(key => {
      Object.defineProperty(this, key, {
        configurable: true,
        enumerable: true,
        get: () => this.$options[parts][key],
        set: (val) => this.$options[parts][key] = val
      })
    })
  }

  _update () {
    const tree = templateParser(this.$options.render.call(this), this)
    const datas = diff(this._oldTree, tree)
    if (!datas) return
    this._oldTree = tree
    return callNative({ datas })
  }

  _render () {
    return viewRender(this._oldTree = templateParser(this.$options.render.call(this), this))
  }

  __h__ (tag, attr, children) {
    return new VNode(tag, attr, children.map((child) => {
      if (typeof child === 'string') {
        return VNode(undefined, undefined, undefined, child)
      } else {
        return child
      }
    }))
  }
}

initGlobalApit(Hero)

